package com.macro.mall.pay.service.wechat.impl;

import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.macro.mall.boot.wechatpay.config.WxPayConfiguration;
import com.macro.mall.common.api.enums.EnvironmentEnum;
import com.macro.mall.common.api.exception.BusinessException;
import com.macro.mall.common.api.util.BigDecimalUtils;
import com.macro.mall.common.api.util.StringUtils;
import com.macro.mall.common.configuration.AppEnvironmentConfiguration;
import com.macro.mall.oms.entity.OrderEntity;
import com.macro.mall.oms.service.order.OrderService;
import com.macro.mall.pay.service.wechat.WeChatPayService;
import com.macro.mall.pay.service.wechat.bo.CreateH5PrePayInfoInput;
import com.macro.mall.pay.service.wechat.bo.CreateJsApiPrePayInfoInput;
import com.macro.mall.pay.service.wechat.bo.CreateJsApiPrePayInfoOutput;
import com.macro.mall.pay.service.wechat.bo.WeChatRefundInput;
import com.macro.mall.ums.entity.WxMemberEntity;
import com.macro.mall.ums.service.account.WxMemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;

/**
 * class
 *
 * @author xuyanjun
 * @date 2019-12-10
 */
@Slf4j
@Service
public class WeChatPayServiceImpl implements WeChatPayService {

    @Autowired
    private OrderService orderService;

    @Autowired
    private WxMemberService wxMemberService;

    @Autowired
    private AppEnvironmentConfiguration appEnvironmentConfiguration;

    /**
     * 创建jsapi预支付信息
     *
     * @param input input
     * @return jsapi预支付信息
     */
    @Override
    public CreateJsApiPrePayInfoOutput createJsApiPrePayInfo(CreateJsApiPrePayInfoInput input) {
        OrderEntity orderEntity = orderService.getById(input.getOrderId());

        String attach = orderEntity.getId().toString();

        WxMemberEntity wxUserEntity = wxMemberService.getByMemberId(orderEntity.getMemberId());

        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
        wxPayUnifiedOrderRequest.setBody("订单支付");
        wxPayUnifiedOrderRequest.setOutTradeNo(orderEntity.getOrderSn() + "-" + orderEntity.getId());
        wxPayUnifiedOrderRequest.setTotalFee(BigDecimalUtils.fromYuanToFeng(orderEntity.getPayAmount()));
        wxPayUnifiedOrderRequest.setSpbillCreateIp(input.getClientIp());
        wxPayUnifiedOrderRequest.setNotifyUrl(input.getCallbackNotifyUrl());
        wxPayUnifiedOrderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
        wxPayUnifiedOrderRequest.setAttach(attach);
        wxPayUnifiedOrderRequest.setOpenid(wxUserEntity.getWxOpenId());
        wxPayUnifiedOrderRequest.setSignType(WxPayConstants.SignType.MD5);

//        if (EnvironmentEnum.DEV.equals(appEnvironmentConfiguration.getEnvironmentEnum()) || EnvironmentEnum.TEST.equals(appEnvironmentConfiguration.getEnvironmentEnum())) {
//            wxPayUnifiedOrderRequest.setTotalFee(1);
//        }

        // wxPayUnifiedOrderRequest.setTotalFee(1);

        WxPayMpOrderResult wxPayMpOrderResult = null;
        try {
            WxPayService wxPayService = WxPayConfiguration.getWxPayServiceByBusinessAppId(input.getSourceEnum().getValue());

            wxPayMpOrderResult = wxPayService.createOrder(wxPayUnifiedOrderRequest);

            CreateJsApiPrePayInfoOutput output = new CreateJsApiPrePayInfoOutput();
            output.setNonceStr(wxPayMpOrderResult.getNonceStr())
                    .setTimeStamp(wxPayMpOrderResult.getTimeStamp())
                    .setPaySign(wxPayMpOrderResult.getPaySign())
                    .setPackageValue(wxPayMpOrderResult.getPackageValue())
                    .setSignType(wxPayMpOrderResult.getSignType());

            return output;

        } catch (WxPayException e) {
            log.error(e.getMessage(), e);
            log.error("微信JSAPI支付失败input:{},result:{}", JSON.toJSONString(input), JSON.toJSONString(wxPayMpOrderResult));

            throw new BusinessException("微信JSAPI支付失败。");
        }
    }

    /**
     * 微信退款
     *
     * @param input input
     */
    @Override
    public void refund(WeChatRefundInput input) {
        OrderEntity orderEntity = orderService.getById(input.getOrderId());
        Assert.isTrue(orderEntity.getPaymentTime() != null, "没有支付的订单不能退款。");

        String tradeNo = orderEntity.getOrderSn() + "-" + orderEntity.getId();

        // 3、调用微信退款接口
        WxPayRefundRequest request = WxPayRefundRequest.newBuilder()
                .outTradeNo(tradeNo)
                .refundFee(BigDecimalUtils.fromYuanToFeng(input.getRefundAmount()))
                .outRefundNo("ret-" + tradeNo)
                .totalFee(BigDecimalUtils.fromYuanToFeng(orderEntity.getPayAmount()))
                .notifyUrl(input.getCallbackNotifyUrl())
                .build();

        WxPayRefundResult wxPayRefundResult = null;
        try {
            WxPayService wxPayService = WxPayConfiguration.getWxPayServiceByBusinessAppId(input.getSourceEnum().getValue());

            wxPayRefundResult = wxPayService.refund(request);
            Assert.isTrue("SUCCESS".equals(wxPayRefundResult.getReturnCode()), "退款申请失败");

        } catch (WxPayException e) {
            log.error(e.getMessage(), e);
            log.error("微信退款失败input:{},result:{}", JSON.toJSONString(input), JSON.toJSONString(wxPayRefundResult));

            throw new BusinessException("微信退款失败。");
        }

    }

    /**
     * 创建H5预支付信息
     *
     * @param input input
     * @return H5跳转链接
     */
    @Override
    public String createH5PrePayInfo(CreateH5PrePayInfoInput input) {
        OrderEntity orderEntity = orderService.getById(input.getOrderId());

        String attach = orderEntity.getId().toString();

        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
        wxPayUnifiedOrderRequest.setBody("订单支付");
        wxPayUnifiedOrderRequest.setOutTradeNo(orderEntity.getOrderSn() + "-" + orderEntity.getId());
        wxPayUnifiedOrderRequest.setTotalFee(BigDecimalUtils.fromYuanToFeng(orderEntity.getPayAmount()));
        wxPayUnifiedOrderRequest.setSpbillCreateIp(input.getClientIp());
        wxPayUnifiedOrderRequest.setNotifyUrl(input.getCallbackNotifyUrl());
        wxPayUnifiedOrderRequest.setTradeType(WxPayConstants.TradeType.MWEB);
        wxPayUnifiedOrderRequest.setAttach(attach);
        wxPayUnifiedOrderRequest.setSignType(WxPayConstants.SignType.MD5);

        if (EnvironmentEnum.DEV.equals(appEnvironmentConfiguration.getEnvironmentEnum()) || EnvironmentEnum.TEST.equals(appEnvironmentConfiguration.getEnvironmentEnum())) {
            wxPayUnifiedOrderRequest.setTotalFee(1);
        }

        try {
            WxPayService wxPayService = WxPayConfiguration.getWxPayServiceByBusinessAppId(input.getSourceEnum().getValue());

            WxPayMwebOrderResult wxPayMwebOrderResult = wxPayService.createOrder(wxPayUnifiedOrderRequest);

            String mwebUrl = wxPayMwebOrderResult.getMwebUrl();

            if (StringUtils.isNotBlank(input.getRedirectUrl())) {
                String encodeRedirectUrl = URLEncoder.encode(input.getRedirectUrl(), "utf-8");
                mwebUrl += "&redirect_url=" + encodeRedirectUrl;
            }

            return mwebUrl;

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            log.error("微信H5支付失败input:{}", JSON.toJSONString(input));

            throw new BusinessException("微信H5支付失败。");
        }
    }
}
